package framework.ai;

/**
 * The Reversi Module with build-in AI
 * @author Stephan Veenstra/Henderikus Harms
 * @version 0.1
 */
public class ReversiAI_WORKING extends AbstractAIModule {

	
	private final static int BOARD_WIDTH = 8;
	private final static int BOARD_HEIGHT = 8;
	private final static int DEPTH = 7;
	private final static String GAME_TYPE = "Reversi";
	private static final int[][] DIRECTIONS = new int[][]{
		{-1,-1}, //N-W
		{0,-1},	 //N	
		{1,-1},	 //N-E
		{1,0},	 //E
		{1,1},	 //S-E
		{0,1},	 //S
		{-1,1},	 //S-W
		{-1,0}	 //W
	};
	
	public ReversiAI_WORKING() {
		super(BOARD_WIDTH,BOARD_HEIGHT, GAME_TYPE);
		this.initBoard();
	}
	
	public void doMove(int player, int move){
		
		int row = move/BOARD_HEIGHT;
		int col = move%BOARD_WIDTH;
		
		if(isValidMove(player, move)){
			this.board = this.place(this.board, move, player);
//			board[row][col] = player;
		}
	}
	
	@Override 
	public void initBoard() {
		// Set the start pieces
		board[4][3] = 1;
		board[3][4] = 1;
		board[3][3] = 2;
		board[4][4] = 2;
	};

	@Override
	public Integer getBestMove(int player) { return 1; }
	
	public int[][] place(int[][] gameBoard, int move, int player) {
		
		int col = move % BOARD_WIDTH;
		int row = move / BOARD_HEIGHT;
		
		int[][] game = gameBoard;
//		if(isValidMove(player, move, gameBoard)) {
			game[row][col] = player;
			game = this.flipAllPieces(player, move, gameBoard);
//		}
		
		return game;
	}
	
	@Override
	public boolean isValidMove(int player, int move) {
		
		int row = move / BOARD_HEIGHT;
		int col = move % BOARD_WIDTH;
		
		if(player == this.getCurrentPlayer()){
			if((row >= 0 && row < BOARD_HEIGHT) && (col >=0 && col < BOARD_WIDTH)){
				if(board[row][col] == EMPTY){
					int points = getTotalPoints(player, move, board);
					if(points > 0) {
						return true;
					}
				}
			}
		}
		return false;
	}
	
	public boolean isValidMove(int player, int move, int[][]gameBoard){
		
		int col = move % BOARD_WIDTH;
		int row = move / BOARD_HEIGHT;
		
		if(player == this.getCurrentPlayer()){
			if((row >= 0 && row < BOARD_HEIGHT) && (col >=0 && col < BOARD_WIDTH)){
				if(gameBoard[row][col] == EMPTY){
					if(getTotalPoints(player, move, gameBoard) > 0){
						return true;
					}
				}
			}
		}
		return false;
	}
	
	private int getPointsInDirection(int player, int startX, int startY, int offsetX, int offsetY,int[][] gameBoard){
		
		int x = startX+offsetX;
		int y = startY+offsetY;
		
		int points = 0;
		while(x < getWidth() && x >= 0 && y < getHeight() && y >= 0){
			if(gameBoard[y][x] == player){
				return points;
			}else if(gameBoard[y][x] == EMPTY){
				return 0;
			}else{
				points++;
				x+=offsetX;
				y+=offsetY;
			}
		}
		return 0;
	}
	
	/**
	 * flip pieces ai board
	 * @param player
	 * @param startX
	 * @param startY
	 * @param offsetX
	 * @param offsetY
	 * @param gameBoard
	 * @return
	 */
	private int[][] flipGameBoardPieces(int player, int startX, int startY, int offsetX, int offsetY,int[][] gameBoard){
		
		int x = startX+offsetX;
		int y = startY+offsetY;
		
		int[][] game = gameBoard;
		
		if(player == EMPTY){
			player = this.getOpponent();
		}
		
		while(x < getWidth() && x >= 0 && y < getHeight() && y >= 0 && game[y][x] != player){
			if(game[y][x] == this.getOpponent()){
				game[y][x] = player;
			}
			x+=offsetX;
			y+=offsetY;
		}
		return game;
	}
	
	/**
	 * Check the maximum amount of point the player can collect with this move
	 * @param player
	 * @param x
	 * @param y
	 * @return
	 */
	private int getTotalPoints(int player,int move, int[][]gameBoard){
		
		int col = move % BOARD_WIDTH;
		int row = move / BOARD_HEIGHT;
		
		int points = 0;
		
		for(int[] direction : ReversiAI_WORKING.DIRECTIONS) {
			points += getPointsInDirection(player,col,row,direction[0],direction[1], gameBoard);
		};
		
		return points;
	}
	
	/**
	 * Check the maximum amount of point the player can collect with this move
	 * @param player
	 * @param x
	 * @param y
	 * @return
	 */
	private int[][] flipAllPieces(int player,int move, int[][]gameBoard){
		
		int col = move % BOARD_WIDTH;
		int row = move / BOARD_HEIGHT;
		
		int[][] board = gameBoard;
		
		for(int[] direction : ReversiAI_WORKING.DIRECTIONS) {
			if(getPointsInDirection(player,col,row,direction[0],direction[1],gameBoard) > 0) {
				board = flipGameBoardPieces(player,col,row,direction[0],direction[1], gameBoard);
			};
		};
		
		return board;
	}
	
	private int getCurrentScore(int player){
		int score = 0;
		for(int i = 0; i > getHeight()*getWidth(); i++){
			if(board[i%getWidth()][i/getWidth()] == player){
				score++;
			}
		}
		return score;
	}
	
	/**
	 * Check if both or one player still can make a move
	 * @return
	 */
	private boolean gameOver(){
		for(int i = 0; i > getHeight()*getWidth(); i++){
			if(board[i%getWidth()][i/getWidth()] == EMPTY){
				if(isValidMove(P1, i) || isValidMove(P2, i)){
					return false;
				}
			}
		}
		return true;
	}

	@Override
	protected int getState(int player) {
		if(gameOver()){
			int p1Score = getCurrentScore(P1);
			int p2score = getCurrentScore(P2);
			if(p1Score == p2score){
				return DRAW;
			}else if(p1Score > p2score){
				return player == P1 ? WIN : LOSE;
			}else{
				return player == P2 ? WIN : LOSE;
			}
		}
		return UNKNOWN;
	}
	
}
